#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <errno.h>

#define SECTOR_SIZE 512

FILE *fp;
FILE *c_fp;
int friend_pid;

typedef unsigned char byte;

typedef struct
{
	int sector_num;
	int updated;  //0 or 1
	int finished; //0 or 1
	byte data[SECTOR_SIZE];  //Each character is byte sized
} test_struct;


int main(int argc, char *argv[])
{
	test_struct my_struct;
	my_struct.sector_num = 0;
	//Mapping memory
	int shm_id;
	char filename[255];
	int count = 0;
	off_t num_sectors = 0;
	int sector_data = open("sector_data", O_RDWR|O_CREAT);

	sprintf(filename, "/Ring_buff_%d", (int)getpid());	//filename will be the name of shared memory object
	shm_id = shm_open(filename, O_RDWR|O_CREAT, 0555);   //Creates shared memory or ring buffer for client

	if(shm_id == -1)
		printf("client shm_open failed\n");

	if(ftruncate(shm_id, sizeof(test_struct))==-1)		//Allocates memory for shared memory object
		printf("truncate failed\n");

	test_struct* shared_addr;

	//Maps the shared memory object to the process's address space
	shared_addr = mmap(0,  //Let kernel find memory
				sizeof(test_struct),  //Length
				PROT_WRITE|PROT_READ, //Protection
				MAP_SHARED ,		//Flags
		        shm_id,				//fid
		        0);		//Offset

	if(shared_addr == MAP_FAILED)
	{
		fprintf( stderr, "client mmap failed: %s\n",
		            strerror( errno ) );
		        return EXIT_FAILURE;
	}

	//*shared_addr = my_struct;
	shared_addr->sector_num = (getpid()%10);
	shared_addr->updated = 0;
	shared_addr->finished = 0;

	//Flush cached data in address space to the shared memory object, invalidating everyone else's cached data
	msync(shared_addr, sizeof(test_struct), MS_SYNC|MS_INVALIDATE);

	//When started, send signal to server for registration and to inform of where ring buffer is
	fp= fopen("ch_id", "a+");

	c_fp = fopen("clients", "a+");

	fprintf(c_fp, "Client %d has arrived with %s\n", (int)getpid(), filename);
	if(fscanf(fp, "%d, %ld", &friend_pid, &num_sectors)!=2)
	{
		printf("Reading ch_id file failed\n");
	}
	kill(friend_pid,SIGUSR1); //Sends this signal to all processes it has perms to, hopefully the server

	printf("Signal sent\n");
	fclose(c_fp);
	//sleep(20);
	//Wait until server updates shared memory
here:
	while(shared_addr->updated == 0)
	{
		//Sit and wait here
	};
	++count;
	//sleep(5);
	shared_addr->updated = 0;
	msync(shared_addr, sizeof(test_struct), MS_SYNC|MS_INVALIDATE);
	if(count < ((getpid()%5)*5))
		goto here;
	if(write(sector_data, shared_addr->data , SECTOR_SIZE)!=SECTOR_SIZE)
								printf("Writing to file sector data failed\n");
	shared_addr->finished = 1;
	msync(shared_addr, sizeof(test_struct), MS_SYNC|MS_INVALIDATE);
	printf("Server updated to %d from %ld\n", shared_addr->sector_num, getpid());

	sleep(5);
	close(shm_id);


	return 0;
}
